#ifndef AT_NETWORK_SOCKET_h
#define AT_NETWORK_SOCKET_h

#include <queue>
#include "Client.h"

#include "AtNetworkUrc.h"
#include "AtNetworkDevice.h"

#include "base_define.h"

#ifndef AT_SOCKET_CMD
#define AT_SOCKET_CMD 32
#endif

#ifndef AT_SOCKET_ERR
#define AT_SOCKET_ERR 3
#endif

#ifndef AT_SOCKET_BUFFER
#define AT_SOCKET_BUFFER 2048
#endif

class AtNetworkSocket : public Client {
  protected:
    std::queue<char> *queue;

    AtNetworkDevice *device;

    /**
     * 连接状态
     */
    uint8_t _connected;

    /**
     * 错误次数(3次以上会导致连接断开)
     */
    uint8_t _error;

    /**
     * 连接方式 ：TCP/UDP
     */
    GSM_STRING mode;

    /**
     * 连接编号(从0开始)
     */
    uint8_t cid;

  public:
    AtNetworkSocket(AtNetworkDevice *device, GSM_STRING mode, uint8_t cid = 0) {
      this->queue = new std::queue<char>();

      this->device = device;
      this->mode = mode;
      this->cid = cid;
    };

    ~AtNetworkSocket() {
      delete this->queue;
    }

    /**
     * 连接到指定IP:PORT
     * @param ip   IP地址
     * @param port 端口
     */
    virtual inline int connect(IPAddress ip, uint16_t port) {
      return this->connect(ip.toString().c_str(), port);
    }

    /**
     * 连接到指定IP:PORT
     * @param host IP地址
     * @param port 端口
     */
    virtual inline int connect(const char *host, uint16_t port) {
      if (host != NULL && this->device->device_lock(1000)) {
        size_t result = this->connect0(host, port);

        this->device->device_unlock();

        return result;
      }

      return -1;
    }

    /**
     * 写入一个字节的数据
     * @param data 数据
     */
    virtual inline size_t write(uint8_t data) {
      return this->write(&data, 1);
    }

    /**
     * 写入一段数据
     * @param buf 数据
     * @param size 长度
     */
    virtual inline size_t write(const uint8_t *buf, size_t size) {
      if (size > 0 && this->device->device_lock(1000)) {
        size_t result = this->write0(buf, size);

        this->device->device_unlock();

        return result;
      }

      return CONNECT_ERR_0;
    }

    /**
     * 获取缓冲区数据长度
     */
    virtual inline int available() {
      return this->queue->size();
    }

    /**
     * 读取一个字节的数据
     */
    virtual inline int read() {
      if (this->queue->empty()) {
        return -1;
      }

      int t = this->queue->front();
      if (t >= 0) {
        this->queue->pop();
      }

      return t;
    }

    /**
     * 读取指定长度的数据
     * @param buf 数据缓冲区
     * @param size 数据长度
     */
    virtual inline int read(uint8_t *buf, size_t size) {
      for (size_t i = 0; i < size; i++) {
        int temp = this->read();
        if (temp == -1) {
          return i;
        }

        buf[i] = temp;
      }

      return size;
    }

    /**
     * 读取一个字节数据(不删除)
     */
    virtual inline int peek() {
      if (this->queue->empty()) {
        return -1;
      }

      return this->queue->front();
    }

    /**
     * 将待发送数据推出
     */
    virtual inline void flush() {
      this->device->_stream->flush();
    }

    /**
     * 断开连接
     */
    virtual inline void stop() {
      if (this->device->device_lock(1000)) {
        this->disconnect0(this->cid);

        this->device->device_unlock();
      }
    }

    /**
     * 获取连接状态
     */
    virtual inline uint8_t connected() {
      return this->_connected;
    }

    virtual inline operator bool() {
      return this->cid != -1;
    }

    /**
     * URC回调接口函数(收到数据)
     */
    virtual void urcWithClose(void *param) = 0;

    /**
     * URC回调接口函数(收到数据)
     */
    virtual void urcWithRecv(void *param) = 0;

  protected:
    /**
     * 写入一段数据
     * @param buf 数据
     * @param size 长度
     */
    virtual size_t write0(const uint8_t *buf, size_t size) = 0;

    /**
     * 连接到指定IP:PORT
     * @param host IP地址
     * @param port 端口
     */
    virtual int connect0(const char *host, uint16_t port) = 0;

    /**
     * 断开连接
     */
    virtual void disconnect0(uint8_t cid = 0) = 0;
};

#endif